/*
 * Display.c
 *
 *  Created on: 10.9.2013
 *      Author: David
 */

#include <util/delay.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>

#include "Display.h"
#include "Dio.h"

#define DELAY_BETWEEN_SEG 100
#define NO_OF_SEGS 21

unsigned char SelfTestSegmentsSequence[NO_OF_SEGS] /*PROGMEM*/ = {32,22,8,7,2,12,23,24,25,27,15,5,6,3,4,20,21,13,14,30,31};

unsigned char Units[10] [7] =
{
		{23,24,25,27,30,31,0}, //0
		{0,24,25,0,0,0,0}, //1
		{23,24,0,27,30,0,32}, //2
		{23,24,25,27,0,0,32}, //3
		{0,24,25,0,0,31,32}, //4
		{23,0,25,27,0,31,32}, //5
		{23,0,25,27,30,31,32}, //6
		{23,24,25,0,0,0,0}, //7
		{23,24,25,27,30,31,32}, //8
		{23,24,25,27,0,31,32}  //9
};

unsigned char Teens[10] [7] =
{
		{12,13,14,15,20,21,0}, //0
		{0,13,14,0,0,0,0}, //1
		{12,13,0,15,20,0,22}, //2
		{12,13,14,15,0,0,22}, //3
		{0,13,14,0,0,21,22}, //4
		{12,0,14,15,0,21,22}, //5
		{12,0,14,15,20,21,22}, //6
		{12,13,14,0,0,0,0}, //7
		{12,13,14,15,20,21,22}, //8
		{12,13,14,15,0,21,22}  //9
};

unsigned char Hundreds[10] [7] =
{
		{2,3,4,5,6,7,0}, //0
		{0,3,4,0,0,0,0}, //1
		{2,3,0,5,6,0,8}, //2
		{2,3,4,5,0,0,8}, //3
		{0,3,4,0,0,7,8}, //4
		{2,0,4,5,0,7,8}, //5
		{2,0,4,5,6,7,8}, //6
		{2,3,4,0,0,0,0}, //7
		{2,3,4,5,6,7,8}, //8
		{2,3,4,5,0,7,8}  //9
};


static void DisplayOneSeg(unsigned char segNo)
{
	unsigned char i;

	IO_SET(LED_DRV_IN_DATA);
	_delay_us(5);
	IO_SET(LED_DRV_CLK);
	_delay_us(5);

	for (i = 1; i < 36; ++i)
	{
		IO_CLR(LED_DRV_CLK);
		_delay_us(5);
		if(i==SelfTestSegmentsSequence[segNo]) IO_SET(LED_DRV_IN_DATA);
		else IO_CLR(LED_DRV_IN_DATA);
		_delay_us(5);
		IO_SET(LED_DRV_CLK);
		_delay_us(5);
	}

	_delay_us(5);
	IO_CLR(LED_DRV_CLK);
	IO_CLR(LED_DRV_IN_DATA);
	_delay_us(5);
}

static unsigned char IsSegToDislay(unsigned char * seq, unsigned char index, unsigned char testValue)
{
	if(seq[index] == testValue)
	{
		return 1;
	}
	else
	{
		if(index > 0)
		{
			return IsSegToDislay(seq, index - 1, testValue);
		}
		else return 0;
	}
}

static void DisplayNextSeg(unsigned char * seq, unsigned char segNo)
{
	unsigned char i;

	IO_SET(LED_DRV_IN_DATA);
	_delay_us(5);
	IO_SET(LED_DRV_CLK);
	_delay_us(5);

	for (i = 1; i < 36; ++i)
	{
		IO_CLR(LED_DRV_CLK);
		_delay_us(5);
		if(IsSegToDislay(seq, segNo, i) == 1) IO_SET(LED_DRV_IN_DATA);
		else IO_CLR(LED_DRV_IN_DATA);
		_delay_us(5);
		IO_SET(LED_DRV_CLK);
		_delay_us(5);
	}

	_delay_us(5);
	IO_CLR(LED_DRV_CLK);
	IO_CLR(LED_DRV_IN_DATA);
	_delay_us(5);
}

void Display_SelfTest()
{
	unsigned char i;

	IO_CLR(LED_DRV_CLK);
	IO_CLR(LED_DRV_IN_DATA);

	IO_OUTPUT(LED_DRV_CLK);
	IO_OUTPUT(LED_DRV_IN_DATA);

	Display_Off();

	for (i = 0; i < NO_OF_SEGS; ++i)
	{
		DisplayNextSeg(SelfTestSegmentsSequence, i);
		wdt_reset();
		_delay_ms(DELAY_BETWEEN_SEG);
	}
	wdt_reset();
	_delay_ms(500);
	wdt_reset();
}

void Display_Number(unsigned int numberToDisplay)
{
    unsigned char h = 0, t = 0, u = 0;
    unsigned char seq[21];
    unsigned char i;

    while (numberToDisplay > 99)
    {
    	numberToDisplay -= 100;
        h++;
    }

    while (numberToDisplay > 9)
    {
    	numberToDisplay -= 10;
        t++;
    }

    u = (unsigned char)numberToDisplay;

    for (i = 0; i < 7; ++i)
    {
    	seq[i]    = Units[u][i];

    	if((t == 0) && (h == 0)) seq[i+7] = 0;
    	else seq[i+7] = Teens[t][i];

    	if(h == 0) seq[i+14] = 0;
    	else seq[i+14] = Hundreds[h][i];
	}


	DisplayNextSeg(seq, 20);
}

void Display_Off()
{
	unsigned char i;

	IO_SET(LED_DRV_IN_DATA);
	_delay_us(5);
	IO_SET(LED_DRV_CLK);
	_delay_us(5);

	for (i = 1; i < 72; ++i)
	{
		IO_CLR(LED_DRV_CLK);
		_delay_us(5);
		IO_CLR(LED_DRV_IN_DATA);
		_delay_us(5);
		IO_SET(LED_DRV_CLK);
		_delay_us(5);
	}

	_delay_us(5);
	IO_CLR(LED_DRV_CLK);
	IO_CLR(LED_DRV_IN_DATA);
	_delay_us(5);
}


/*
for (j = 1; j < 36; ++j)
{
	if((j==1) ||
	  (j==9) ||
	  (j==10) ||
	  (j==11) ||
	  (j==16) ||
	  (j==17) ||
	  (j==18) ||
	  (j==19) ||
	  (j==26) ||
	  (j==28) ||
	  (j==29) ||
	  (j==35) )
			continue;
	IO_SET(LED_DRV_IN_DATA);
	_delay_ms(2);
	IO_SET(LED_DRV_CLK);
	_delay_ms(5);

	for (i = 1; i < 36; ++i)
	{
		IO_CLR(LED_DRV_CLK);
		_delay_ms(20);
		if(i==j) IO_SET(LED_DRV_IN_DATA);
		else IO_CLR(LED_DRV_IN_DATA);
		_delay_ms(2);
		IO_SET(LED_DRV_CLK);
		_delay_ms(5);
	}

	_delay_ms(30);
	IO_CLR(LED_DRV_CLK);
	IO_CLR(LED_DRV_IN_DATA);
	_delay_ms(5);
}
*/
